package com.hfzy.ihk.web.aliyuncall.support.cloudcall.handler.asrcall;

import com.alibaba.fastjson.JSONObject;
import com.hfzy.ihk.common.util.date.DateUtils;
import com.hfzy.ihk.common.util.string.StringTools;
import com.hfzy.ihk.facade.aliyuncall.vo.CallHistory;
import com.hfzy.ihk.web.aliyuncall.biz.PushDataToBLBiz;
import com.hfzy.ihk.web.aliyuncall.biz.PushDataToEsBiz;
import com.hfzy.ihk.web.aliyuncall.constant.*;
import com.hfzy.ihk.web.aliyuncall.support.cloudcall.base.AbstractCallStateHandler;
import com.hfzy.ihk.web.aliyuncall.support.cloudcall.event.AliyunCallStateEvent;
import com.hfzy.ihk.web.aliyuncall.support.websocket.WebSocketUtils;
import com.hfzy.ihk.web.aliyuncall.vo.AliyunCallState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.core.task.TaskExecutor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * Asr智能外呼状态处理类
 */
@Component
@Scope("prototype")
public class AliyunAsrCallStateHandler extends AbstractCallStateHandler<AliyunCallState,AliyunCallStateEvent> {


    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    WebSocketUtils webSocketUtils;

    @Resource
    TaskExecutor pushDataToEsTaskExecutor;

    @Autowired
    PushDataToEsBiz pushDataToEsBiz;


    Logger logger = LoggerFactory.getLogger(AliyunAsrCallStateHandler.class);

    @Override
    protected Map<String, CallHistory> getMemoryCache() {
        return null;
    }

    /**
     * 从缓存中获取记录
     * @param sessionId
     * @return
     */
    @Override
    protected Map<String, String> readRedis(String sessionId) {

        logger.debug("CallStateTaobaoWorkHandler readRedis："+sessionId);

        return  redisTemplate.opsForHash().entries(RedisKey.CALL_HISTORY_RPIX+sessionId);

    }

    /**
     * 读取redis失败
     * @param Data
     * @return
     */
    @Override
    protected String handleReadRedisFailed(AliyunCallState Data) {
        return null;
    }

    /**
     * 写redis
     * @param sessionId
     * @param map
     * @return
     */
    @Override
    protected String writeRedis(String sessionId, Map<String, String> map) {
        if(map.isEmpty()) {
            logger.debug("writeRedis --->map is Empty,");
            return Constants.FAIL;
        }
        redisTemplate.opsForHash().putAll(RedisKey.CALL_HISTORY_RPIX + sessionId, map);
        //超时时间三天
        redisTemplate.expire(RedisKey.CALL_HISTORY_RPIX + sessionId, RedisTimeOut.CACHE_THREE_DAY, TimeUnit.SECONDS);

        return Constants.SUCCESS;
    }


    /**
     * 写redis失败
     * @param sessionId
     * @param map
     * @return
     */
    @Override
    protected String handleWriteRedisFailed(String sessionId, Map<String, String> map) {
        return null;
    }

    /**
     * 判断是否入库操作
     * @param callHistoryMap
     * @param redisMap
     * @param data
     * @return
     */
    @Override
    protected boolean checkCanOrNotPushToBatchInsertQueue(Map<String, String> callHistoryMap, Map<String, String> redisMap, AliyunCallState data) {
        boolean ableInsert = false;
        if (data.getMsgType().equals(AliyunAkInfo.VOICEREPORT)) {
            ableInsert = true;
        }
        return ableInsert;
    }



    /**
     * 将状态消息推送到客户端
     * @param callHistoryMap
     * @param resultMap
     * @throws Exception
     */
    @Override
    protected void pushStateToClient(Map<String, String> callHistoryMap, Map<String, Map<String, String>> resultMap) throws Exception {
        Map<String,String> msgMap = resultMap.get(Constants.CALL_STATE_WORK_HANDLER_MAP_KEY_MSG);
        String sessionId = callHistoryMap.get(Constants.WEB_SOCKET_JSON_KEY_SESSION_ID);

        //呼入暂时不推送数据到客户端
        if("1".equals(callHistoryMap.get(RedisFields.CALL_HISTORY_CALL_TYPE))
                || Constants.WEB_SOCKET_MSG_TYPE_INCOME.equals(msgMap.get(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE))) {
            logger.debug("INCOME msg,dont send to client");
            return;
        }
        if(Constants.WEB_SOCKET_MSG_TYPE_INVALID.equals(msgMap.get(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE))) {
            logger.debug("INVALID msg, dont send to client");
            return;
        }


        String json = JSONObject.toJSONString(msgMap);

        logger.debug("CallStateTaobaoWorkHandler pushStateToClient--->data:"+json);

        String rs = webSocketUtils.pushToClientBySessionId(sessionId, json);
        if(Constants.FAIL.equals(rs) || rs==null)
            logger.error("AliyunCallStateWorkHandler pushStateToClient--->rs:{},sessionId:{}",rs,sessionId);



    }



    /**
     * 呼叫状态推送到客户端失败时的处理
     */
    @Override
    protected void handlePushStateToClientFail() {
        logger.info("handlePushAsrStateToClientFail ....CallState");
    }

    /**
     * 分析数据操作
     * @param callState
     * @param callHistoryMap
     * @return
     * @throws Exception
     */

    @Override
    protected Map<String, Map<String, String>> analyzeCallState(AliyunCallState callState, Map<String, String> callHistoryMap) throws Exception {

        Map<String,Map<String,String>> resultMap = new HashMap<>(2);
        //返回给客户端的map
        Map<String,String> msgMap = new HashMap<>(2);
        Map<String,String> redisSaveMap = new HashMap<>();

        logger.debug("analyze callState:" + callState.toString());
        String  nowDateStr = DateUtils.formatDate(new Date(), DateUtils.DATE_FORMAT_DATETIME_SSS);

        if(callState.getMsgType().equals(AliyunAkInfo.VOICECALLREPORT)){ //呼出中间状态
            switch (callState.getStatus_code()){
                case MsgStatus._200101:  //正在接通主叫 --当做提交成功 该状态不用推送给客户端
                    try {
                        //用于设定当前使用用户是否占线
                        if(callHistoryMap.get(RedisFields.CREATE_USER_ID)!=null) {
                            redisTemplate.opsForHash().put(RedisKey.USER_BUSY, callHistoryMap.get(RedisFields.CREATE_USER_ID), Constants.TRUE);
                        }
                    }catch (Exception e){
                        logger.error("======>call state：{} ",callState.getStatus_code(),e);
                    }

                    msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_INVALID);
                    break;
                case MsgStatus._200201:  //主叫响铃 该状态不用推送给客户端
                    redisSaveMap.put(RedisFields.CALL_HISTORY_MAIN_CALL_RINGING_TIME,  DateUtils.stringFromString(callState.getStatus_time(),DateUtils.DATE_FORMAT_DATETIME_SSS));
                    redisSaveMap.put(RedisFields.CALL_HISTORY_MAIN_CALL_RINGING, Constants.TRUE);
                    redisSaveMap.put(RedisFields.RECEIVE_CALL_HISTORY_MAIN_CALL_RINGING_TIME, nowDateStr);
                    msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_INVALID);
                    break;

                case MsgStatus._200102:  //正在通话 asr 状态这里为正在通话
                    msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_TARGET_ANSWERED);

                    redisSaveMap.put(RedisFields.CALL_HISTORY_MAIN_CALL_ANSWERED, Constants.TRUE);
                    redisSaveMap.put(RedisFields.CALL_HISTORY_MAIN_CALL_ANSWERED_TIME, DateUtils.stringFromString(callState.getStatus_time(), DateUtils.DATE_FORMAT_DATETIME_SSS));
                    redisSaveMap.put(RedisFields.RECEIVE_HISTORY_MAIN_CALL_ANSWERED_TIME, nowDateStr);
                    break;
                case MsgStatus._200100:   //呼叫结束（asr智能外呼）
                    //客户不接->客户无接听
                    //客户接，经纪还没接，客户就挂断->客户挂机
                    //客户接、经纪接->结束通话
                    try {
                        if (callHistoryMap.get(RedisFields.CALL_HISTORY_DISCONNECT_TIME) == null) { //由于会发多次，取第一次和账单那次就好，呼入账单状态回来就入库和推置业



                            redisSaveMap.put(RedisFields.CALL_HISTORY_DISCONNECT_TIME, DateUtils.stringFromString(callState.getStatus_time(), DateUtils.DATE_FORMAT_DATETIME_SSS));
                            redisSaveMap.put(RedisFields.RECEIVE_CALL_HISTORY_DISCONNECT_TIME, nowDateStr);

                            if (!Constants.TRUE.equals(callHistoryMap.get(RedisFields.CALL_HISTORY_MAIN_CALL_ANSWERED))) { //呼叫主叫失败，（各种原因）

                                msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_MAIN_FAILED);
                                msgMap.put(Constants.WEB_SOCKET_JSON_KEY_DESC, Constants.FJ_TELECOM_FAILED_REASON_MAIN_FAILED_4);

                                redisSaveMap.put(RedisFields.CALL_HISTORY_MAIN_CALL_FAILED, Constants.TRUE);
                                redisSaveMap.put(RedisFields.CALL_HISTORY_MAIN_CALL_FAILED_TIME, DateUtils.stringFromString(callState.getStatus_time(), DateUtils.DATE_FORMAT_DATETIME_SSS));
                                redisSaveMap.put(RedisFields.RECEIVE_CALL_HISTORY_MAIN_CALL_FAILED_TIME, nowDateStr);

                            } else { //正常通话结束
                                msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_TARGET_DISCONNECTED);

                            }

                        } else { //多余的状态不推送到客户端
                            msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_INVALID);

                        }
                    }catch (Exception e){ //防止话单比结束状态早回来的情况
                        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_TARGET_DISCONNECTED);
                    }

                    break;
                default: //多余状态不推送到客户端
                    msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_INVALID);
                    break;

            }
        }else if(callState.getMsgType().equals(AliyunAkInfo.VOICEREPORT)){//呼出话务单话务单回来之后才推送持久化服务

            String statusCode = callState.getStatus_code();
            String statusMsg = callState.getStatus_msg();
            if(statusMsg!=null) {
                redisSaveMap.put(RedisFields.CALL_HISTORY_REMARK, statusMsg);
            }
            //手动取消外呼显示取消外呼
            logger.info("aliyun------------------INTERRUPT：{}",callHistoryMap.get(RedisFields.INTERRUPT));

            if(callHistoryMap.get(RedisFields.INTERRUPT)!=null
                    &&Constants.INTERRUPT.toString().equals(callHistoryMap.get(RedisFields.INTERRUPT))){
                redisSaveMap.put(RedisFields.CALL_HISTORY_FAILED_REASON,Constants.LOCAL_MSG_CALL_CANCEL);

            }else if(!MsgStatus._200100.equals(statusCode)){
                redisSaveMap.put(RedisFields.CALL_HISTORY_FAILED_REASON,statusMsg);
            }

            //呼出话单处理
            if(Constants.CALL_OUT.toString().equals(callHistoryMap.get(RedisFields.CALL_HISTORY_CALL_TYPE))){      //处理呼出话单，

                if(StringTools.isNotempty(callState.getDuration())) { //主叫时长

                    redisSaveMap.put(RedisFields.MAIN_CALL_LENGTH, callState.getDuration());
                    redisSaveMap.put(RedisFields.CALL_HISTORY_RECORD_TIME_LENTH, callState.getDuration());
                }

                if(StringTools.isNotempty(callState.getStart_time())) { // 主叫开始时间可能没有这个时间
                    redisSaveMap.put(RedisFields.MAIN_CALL_START_TIME, DateUtils.stringFromString(callState.getStart_time(), DateUtils.DATE_FORMAT_DATETIME_SSS));
                }

                if(StringTools.isNotempty(callState.getEnd_time())){ // 主叫结束时间可能没有这个时间
                    redisSaveMap.put(RedisFields.MAIN_CALL_END_TIME,DateUtils.stringFromString(callState.getEnd_time(),DateUtils.DATE_FORMAT_DATETIME_SSS));
                }


            }
            //话务单回来也不需要发送到客户端
            msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_INVALID);

        }

        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_TIME, nowDateStr);
        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_SESSION_ID, callState.getOut_id());
        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_DATA_ID, callHistoryMap.get(RedisFields.CALL_HISTORY_DATA_ID));
        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_PAGE_FROM, callHistoryMap.get(RedisFields.CALL_HISTORY_PAGE_FROM));
        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MACHINE_FROM, callHistoryMap.get(RedisFields.CALL_HISTORY_MACHINE_FROM));
        resultMap.put(Constants.CALL_STATE_WORK_HANDLER_MAP_KEY_MSG,msgMap);
        resultMap.put(Constants.CALL_STATE_WORK_HANDLER_MAP_KEY_REDIS,redisSaveMap);

        return resultMap;
    }


    /**
     * 保持数据操作
     * @param callHistoryMap
     */
    @Override
    protected void todoSaveCallRcord(Map<String, String> callHistoryMap) {
        try {
            String jsonStr = JSONObject.toJSONString(callHistoryMap);
            pushDataToEsTaskExecutor.execute(() -> {
                pushDataToEsBiz.pushCallHistoryToEs(callHistoryMap.get(RedisFields.CALL_HISTORY_SESSION_ID), jsonStr, RedisKey.CALL_HISTORY_RPIX + callHistoryMap.get(RedisFields.CALL_HISTORY_SESSION_ID));
            });
        }catch (Exception e){
            try {
                redisTemplate.opsForSet().add(RedisKey.PUSH_TO_ES_FAILED_HISTORY, callHistoryMap.get(RedisFields.CALL_HISTORY_SESSION_ID));
            }catch (Exception e1){
                logger.error("将推送ES 失败数据放入redis 失败！sessionId：{}",callHistoryMap.get(RedisFields.CALL_HISTORY_SESSION_ID),e1);
            }
            logger.error("====>推送Es 的线程池爆了",e);
        }

    }


    @Override
    protected void pushRecordToBL(Map<String, String> callHistoryMap) {

    }


}
